package com.datang.litejvm.cmd;

import com.datang.litejvm.constant.ConstantPool;
import com.datang.litejvm.engin.ExecutionResult;
import com.datang.litejvm.engin.Heap;
import com.datang.litejvm.engin.JavaObject;
import com.datang.litejvm.engin.StackFrame;

public class NoOperandCmd extends ByteCodeCommand {
    public NoOperandCmd(ConstantPool pool, String opCode) {
        super(pool, opCode);
    }

    @Override
    public int getLength() {
        return 1;
    }

    @Override
    public String toString() {
        return super.toString();
    }

    @Override
    public void execute(StackFrame frame, ExecutionResult result) {

        if ("".equals(opCode)) {

        } else if (ByteCodeCommand.dup.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 复制操作数栈栈顶的值，并插入到栈顶
             * 复制操作数栈栈顶的值，并将此值压入到操作数栈顶。
             * 如果 value 不是§2.11.1 的表 2.3 中列出的分类一中的数据类型，就不能
             * 使用 dup 指令来复制栈顶值。
             * @date: 22:05 2022/6/16
             **/
            JavaObject javaObject = frame.getOperandStack().peek();
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.aload_0.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 从局部变量表加载一个 reference 类型值到操作数栈中
             * <n>代表当前栈帧（§2.6）中局部变量表的索引值，<n>作为索引定位的局部
             * 变量必须为 reference 类型，称为 objectref。指令执行后，objectref
             * 将会压入到操作数栈栈顶
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getLocalVariableValue(0);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.aload_1.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 从局部变量表加载一个 reference 类型值到操作数栈中
             * <n>代表当前栈帧（§2.6）中局部变量表的索引值，<n>作为索引定位的局部
             * 变量必须为 reference 类型，称为 objectref。指令执行后，objectref
             * 将会压入到操作数栈栈顶
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getLocalVariableValue(1);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.aload_2.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 从局部变量表加载一个 reference 类型值到操作数栈中
             * <n>代表当前栈帧（§2.6）中局部变量表的索引值，<n>作为索引定位的局部
             * 变量必须为 reference 类型，称为 objectref。指令执行后，objectref
             * 将会压入到操作数栈栈顶
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getLocalVariableValue(2);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.aload_3.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 从局部变量表加载一个 reference 类型值到操作数栈中
             * <n>代表当前栈帧（§2.6）中局部变量表的索引值，<n>作为索引定位的局部
             * 变量必须为 reference 类型，称为 objectref。指令执行后，objectref
             * 将会压入到操作数栈栈顶
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getLocalVariableValue(3);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.astore_0.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 将一个 reference 类型数据保存到局部变量表中
             * <n>必须是一个指向当前栈帧（§2.6）局部变量表的索引值，而在操作数栈
             * 栈顶的 objectref 必须是 returnAddress 或者 reference 类型的数据，
             * 这个数据将从操作数栈出栈，然后保存到<n>所指向的局部变量表位置中。
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getOperandStack().pop();
            frame.setLocalVariableValue(0, javaObject);
        } else if (ByteCodeCommand.astore_1.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 将一个 reference 类型数据保存到局部变量表中
             * <n>必须是一个指向当前栈帧（§2.6）局部变量表的索引值，而在操作数栈
             * 栈顶的 objectref 必须是 returnAddress 或者 reference 类型的数据，
             * 这个数据将从操作数栈出栈，然后保存到<n>所指向的局部变量表位置中。
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getOperandStack().pop();
            frame.setLocalVariableValue(1, javaObject);
        } else if (ByteCodeCommand.astore_2.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 将一个 reference 类型数据保存到局部变量表中
             * <n>必须是一个指向当前栈帧（§2.6）局部变量表的索引值，而在操作数栈
             * 栈顶的 objectref 必须是 returnAddress 或者 reference 类型的数据，
             * 这个数据将从操作数栈出栈，然后保存到<n>所指向的局部变量表位置中。
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getOperandStack().pop();
            frame.setLocalVariableValue(2, javaObject);
        } else if (ByteCodeCommand.astore_3.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 将一个 reference 类型数据保存到局部变量表中
             * <n>必须是一个指向当前栈帧（§2.6）局部变量表的索引值，而在操作数栈
             * 栈顶的 objectref 必须是 returnAddress 或者 reference 类型的数据，
             * 这个数据将从操作数栈出栈，然后保存到<n>所指向的局部变量表位置中。
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getOperandStack().pop();
            frame.setLocalVariableValue(3, javaObject);
        } else if (ByteCodeCommand.voidreturn.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 无返回值的方法返回
             * 当前方法的返回值必须被声明为 void。如果当前方法是一个同步（声明为
             * synchronized）方法，那在方法调用时进入或者重入的管程应当被正确更新
             * 状态或退出，就像当前线程执行了 monitorexit 指令一样。如果执行过程当
             * 中没有异常被抛出的话，在当前栈帧操作数栈中所有其他的值都将会被丢弃
             * 掉。
             * 指令执行后，解释器会恢复调用者的栈帧，并且把程序控制权交回到调用者。
             * @date: 11:46 2022/6/17
             **/
            result.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME);
        } else if (ByteCodeCommand.iload_0.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 从局部变量表加载一个 int 类型值到操作数栈中
             * <n>代表一个当前栈帧（§2.6）中局部变量表的索引值，<n>作为索引定位的
             * 局部变量必须为 int 类型，记作 value。指令执行后，value 将会压入到操
             * 作数栈栈顶
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getLocalVariableValue(0);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.iload_1.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 从局部变量表加载一个 int 类型值到操作数栈中
             * <n>代表一个当前栈帧（§2.6）中局部变量表的索引值，<n>作为索引定位的
             * 局部变量必须为 int 类型，记作 value。指令执行后，value 将会压入到操
             * 作数栈栈顶
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getLocalVariableValue(1);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.iload_2.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 从局部变量表加载一个 int 类型值到操作数栈中
             * <n>代表一个当前栈帧（§2.6）中局部变量表的索引值，<n>作为索引定位的
             * 局部变量必须为 int 类型，记作 value。指令执行后，value 将会压入到操
             * 作数栈栈顶
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getLocalVariableValue(2);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.iload_3.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 从局部变量表加载一个 int 类型值到操作数栈中
             * <n>代表一个当前栈帧（§2.6）中局部变量表的索引值，<n>作为索引定位的
             * 局部变量必须为 int 类型，记作 value。指令执行后，value 将会压入到操
             * 作数栈栈顶
             * @date: 10:18 2022/6/17
             **/
            JavaObject javaObject = frame.getLocalVariableValue(3);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.iadd.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description:int 类型数据相加
             * value1 和 value2 都必须为 int 类型数据，指令执行时，value1 和 value2
             * 从操作数栈中出栈，将这两个数值相加得到 int 类型数据 result
             * （result=value1＋value2），最后 result 被压入到操作数栈中。
             * 运算的结果使用低位在高地址（Low-Order Bites）的顺序、按照二进制补
             * 码形式存储在 32 位空间中，其数据类型为 int。如果发生了上限溢出，那结
             * 果的符号可能与真正数学运算结果的符号相反。
             * 尽管可能发生上限溢出，但是 iadd 指令的执行过程中不会抛出任何运行时异
             * 常
             * @date: 17:33 2022/6/17
             **/
            JavaObject javaObject1 = frame.getOperandStack().pop();
            JavaObject javaObject2 = frame.getOperandStack().pop();
            int a = javaObject1.getIntValue();
            int b = javaObject2.getIntValue();
            int c = a + b;
            JavaObject javaObject = Heap.getInstance().newInt(c);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.istore_0.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description:将一个 int 类型数据保存到局部变量表中
             * <n>必须是一个指向当前栈帧（§2.6）局部变量表的索引值，而在操作数栈
             * 栈顶的 value 必须是 int 类型的数据，这个数据将从操作数栈出栈，然后保
             * 存到<n>所指向的局部变量表位置中。
             * @date: 17:43 2022/6/17
             **/
            JavaObject javaObject = frame.getOperandStack().pop();
            frame.setLocalVariableValue(0, javaObject);
        } else if (ByteCodeCommand.istore_1.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description:将一个 int 类型数据保存到局部变量表中
             * <n>必须是一个指向当前栈帧（§2.6）局部变量表的索引值，而在操作数栈
             * 栈顶的 value 必须是 int 类型的数据，这个数据将从操作数栈出栈，然后保
             * 存到<n>所指向的局部变量表位置中。
             * @date: 17:43 2022/6/17
             **/
            JavaObject javaObject = frame.getOperandStack().pop();
            frame.setLocalVariableValue(1, javaObject);
        } else if (ByteCodeCommand.istore_2.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description:将一个 int 类型数据保存到局部变量表中
             * <n>必须是一个指向当前栈帧（§2.6）局部变量表的索引值，而在操作数栈
             * 栈顶的 value 必须是 int 类型的数据，这个数据将从操作数栈出栈，然后保
             * 存到<n>所指向的局部变量表位置中。
             * @date: 17:43 2022/6/17
             **/
            JavaObject javaObject = frame.getOperandStack().pop();
            frame.setLocalVariableValue(2, javaObject);
        } else if (ByteCodeCommand.istore_3.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description:将一个 int 类型数据保存到局部变量表中
             * <n>必须是一个指向当前栈帧（§2.6）局部变量表的索引值，而在操作数栈
             * 栈顶的 value 必须是 int 类型的数据，这个数据将从操作数栈出栈，然后保
             * 存到<n>所指向的局部变量表位置中。
             * @date: 17:43 2022/6/17
             **/
            JavaObject javaObject = frame.getOperandStack().pop();
            frame.setLocalVariableValue(3, javaObject);
        } else if (ByteCodeCommand.iconst_0.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 将 int 类型数据压入到操作数栈中
             * 将 int 类型的常量<i>（－1，0，1，2，3，4 或者 5）压入到操作数栈中。
             * @date: 17:47 2022/6/17
             **/
            JavaObject javaObject = Heap.getInstance().newInt(0);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.iconst_1.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 将 int 类型数据压入到操作数栈中
             * 将 int 类型的常量<i>（－1，0，1，2，3，4 或者 5）压入到操作数栈中。
             * @date: 17:47 2022/6/17
             **/
            JavaObject javaObject = Heap.getInstance().newInt(1);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.iconst_2.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 将 int 类型数据压入到操作数栈中
             * 将 int 类型的常量<i>（－1，0，1，2，3，4 或者 5）压入到操作数栈中。
             * @date: 17:47 2022/6/17
             **/
            JavaObject javaObject = Heap.getInstance().newInt(2);
            frame.getOperandStack().push(javaObject);
        } else if (ByteCodeCommand.iconst_3.equals(opCode)) {
            /**
             * @author: 顶风少年
             * @Description: 将 int 类型数据压入到操作数栈中
             * 将 int 类型的常量<i>（－1，0，1，2，3，4 或者 5）压入到操作数栈中。
             * @date: 17:47 2022/6/17
             **/
            JavaObject javaObject = Heap.getInstance().newInt(3);
            frame.getOperandStack().push(javaObject);
        } else {
            throw new RuntimeException("Sorry, the java instruction " + opCode + " has not been implemented");
        }
    }
}
